home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / fileutil.13 / fileutil / fileutils-3.13 / lib / getdate.y < prev    next >
Encoding:
Lex Description  |  1996-05-13  |  23.4 KB  |  987 lines

  1. %{
  2. /*
  3. **  Originally written by Steven M. Bellovin <smb@research.att.com> while
  4. **  at the University of North Carolina at Chapel Hill.  Later tweaked by
  5. **  a couple of people on Usenet.  Completely overhauled by Rich $alz
  6. **  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  7. **  send any email to Rich.
  8. **
  9. **  This grammar has 10 shift/reduce conflicts.
  10. **
  11. **  This code is in the public domain and has no copyright.
  12. */
  13. /* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
  14. /* SUPPRESS 288 on yyerrlab *//* Label unused */
  15.  
  16. #ifdef HAVE_CONFIG_H
  17. #include <config.h>
  18.  
  19. #ifdef FORCE_ALLOCA_H
  20. #include <alloca.h>
  21. #endif
  22. #endif
  23.  
  24. /* Since the code of getdate.y is not included in the Emacs executable
  25.    itself, there is no need to #define static in this file.  Even if
  26.    the code were included in the Emacs executable, it probably
  27.    wouldn't do any harm to #undef it here; this will only cause
  28.    problems if we try to write to a static variable, which I don't
  29.    think this code needs to do.  */
  30. #ifdef emacs
  31. #undef static
  32. #endif
  33.  
  34. #include <stdio.h>
  35. #include <ctype.h>
  36.  
  37. #if    defined (vms)
  38. #include <types.h>
  39. #include <time.h>
  40. #else
  41. #include <sys/types.h>
  42. #ifdef TIME_WITH_SYS_TIME
  43. #include <sys/time.h>
  44. #include <time.h>
  45. #else
  46. #ifdef HAVE_SYS_TIME_H
  47. #include <sys/time.h>
  48. #else
  49. #include <time.h>
  50. #endif
  51. #endif
  52.  
  53. #ifdef timezone
  54. #undef timezone /* needed for sgi */
  55. #endif
  56.  
  57. #if defined (HAVE_SYS_TIMEB_H)
  58. #include <sys/timeb.h>
  59. #else
  60.  
  61. /* get_date uses the obsolete `struct timeb' in its interface!  FIXME.
  62.    Since some systems don't have it, we define it here;
  63.    callers must do likewise.  */
  64. struct timeb
  65.   {
  66.     time_t        time;        /* Seconds since the epoch    */
  67.     unsigned short    millitm;    /* Field not used        */
  68.     short        timezone;    /* Minutes west of GMT        */
  69.     short        dstflag;    /* Field not used        */
  70. };
  71. #endif /* defined (HAVE_SYS_TIMEB_H) */
  72.  
  73. #endif    /* defined (vms) */
  74.  
  75. #if defined (STDC_HEADERS) || defined (USG)
  76. #include <string.h>
  77. #endif
  78.  
  79. /* Some old versions of bison generate parsers that use bcopy.
  80.    That loses on systems that don't provide the function, so we have
  81.    to redefine it here.  */
  82. #if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
  83. #define bcopy(from, to, len) memcpy ((to), (from), (len))
  84. #endif
  85.  
  86. extern struct tm    *gmtime ();
  87. extern struct tm    *localtime ();
  88.  
  89. #define yyparse getdate_yyparse
  90. #define yylex getdate_yylex
  91. #define yyerror getdate_yyerror
  92.  
  93. static int yylex ();
  94. static int yyerror ();
  95.  
  96. #define EPOCH        1970
  97. #define DOOMSDAY    2038
  98. #define HOUR(x)        ((time_t)(x) * 60)
  99. #define SECSPERDAY    (24L * 60L * 60L)
  100.  
  101. #define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
  102.  
  103. /*
  104. **  An entry in the lexical lookup table.
  105. */
  106. typedef struct _TABLE {
  107.     const char    *name;
  108.     int        type;
  109.     time_t    value;
  110. } TABLE;
  111.  
  112.  
  113. /*
  114. **  Daylight-savings mode:  on, off, or not yet known.
  115. */
  116. typedef enum _DSTMODE {
  117.     DSTon, DSToff, DSTmaybe
  118. } DSTMODE;
  119.  
  120. /*
  121. **  Meridian:  am, pm, or 24-hour style.
  122. */
  123. typedef enum _MERIDIAN {
  124.     MERam, MERpm, MER24
  125. } MERIDIAN;
  126.  
  127.  
  128. /*
  129. **  Global variables.  We could get rid of most of these by using a good
  130. **  union as the yacc stack.  (This routine was originally written before
  131. **  yacc had the %union construct.)  Maybe someday; right now we only use
  132. **  the %union very rarely.
  133. */
  134. static char    *yyInput;
  135. static DSTMODE    yyDSTmode;
  136. static time_t    yyDayOrdinal;
  137. static time_t    yyDayNumber;
  138. static int    yyHaveDate;
  139. static int    yyHaveDay;
  140. static int    yyHaveRel;
  141. static int    yyHaveTime;
  142. static int    yyHaveZone;
  143. static time_t    yyTimezone;
  144. static time_t    yyDay;
  145. static time_t    yyHour;
  146. static time_t    yyMinutes;
  147. static time_t    yyMonth;
  148. static time_t    yySeconds;
  149. static time_t    yyYear;
  150. static MERIDIAN    yyMeridian;
  151. static time_t    yyRelMonth;
  152. static time_t    yyRelSeconds;
  153.  
  154. %}
  155.  
  156. %union {
  157.     time_t        Number;
  158.     enum _MERIDIAN    Meridian;
  159. }
  160.  
  161. %token    tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  162. %token    tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
  163.  
  164. %type    <Number>    tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
  165. %type    <Number>    tSEC_UNIT tSNUMBER tUNUMBER tZONE
  166. %type    <Meridian>    tMERIDIAN o_merid
  167.  
  168. %%
  169.  
  170. spec    : /* NULL */
  171.     | spec item
  172.     ;
  173.  
  174. item    : time {
  175.         yyHaveTime++;
  176.     }
  177.     | zone {
  178.         yyHaveZone++;
  179.     }
  180.     | date {
  181.         yyHaveDate++;
  182.     }
  183.     | day {
  184.         yyHaveDay++;
  185.     }
  186.     | rel {
  187.         yyHaveRel++;
  188.     }
  189.     | number
  190.     ;
  191.  
  192. time    : tUNUMBER tMERIDIAN {
  193.         yyHour = $1;
  194.         yyMinutes = 0;
  195.         yySeconds = 0;
  196.         yyMeridian = $2;
  197.     }
  198.     | tUNUMBER ':' tUNUMBER o_merid {
  199.         yyHour = $1;
  200.         yyMinutes = $3;
  201.         yySeconds = 0;
  202.         yyMeridian = $4;
  203.     }
  204.     | tUNUMBER ':' tUNUMBER tSNUMBER {
  205.         yyHour = $1;
  206.         yyMinutes = $3;
  207.         yyMeridian = MER24;
  208.         yyDSTmode = DSToff;
  209.         yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  210.     }
  211.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  212.         yyHour = $1;
  213.         yyMinutes = $3;
  214.         yySeconds = $5;
  215.         yyMeridian = $6;
  216.     }
  217.     | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  218.         yyHour = $1;
  219.         yyMinutes = $3;
  220.         yySeconds = $5;
  221.         yyMeridian = MER24;
  222.         yyDSTmode = DSToff;
  223.         yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  224.     }
  225.     ;
  226.  
  227. zone    : tZONE {
  228.         yyTimezone = $1;
  229.         yyDSTmode = DSToff;
  230.     }
  231.     | tDAYZONE {
  232.         yyTimezone = $1;
  233.         yyDSTmode = DSTon;
  234.     }
  235.     |
  236.       tZONE tDST {
  237.         yyTimezone = $1;
  238.         yyDSTmode = DSTon;
  239.     }
  240.     ;
  241.  
  242. day    : tDAY {
  243.         yyDayOrdinal = 1;
  244.         yyDayNumber = $1;
  245.     }
  246.     | tDAY ',' {
  247.         yyDayOrdinal = 1;
  248.         yyDayNumber = $1;
  249.     }
  250.     | tUNUMBER tDAY {
  251.         yyDayOrdinal = $1;
  252.         yyDayNumber = $2;
  253.     }
  254.     ;
  255.  
  256. date    : tUNUMBER '/' tUNUMBER {
  257.         yyMonth = $1;
  258.         yyDay = $3;
  259.     }
  260.     | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  261.         yyMonth = $1;
  262.         yyDay = $3;
  263.         yyYear = $5;
  264.     }
  265.     | tUNUMBER tSNUMBER tSNUMBER {
  266.         /* ISO 8601 format.  yyyy-mm-dd.  */
  267.         yyYear = $1;
  268.         yyMonth = -$2;
  269.         yyDay = -$3;
  270.     }
  271.     | tUNUMBER tMONTH tSNUMBER {
  272.         /* e.g. 17-JUN-1992.  */
  273.         yyDay = $1;
  274.         yyMonth = $2;
  275.         yyYear = -$3;
  276.     }
  277.     | tMONTH tUNUMBER {
  278.         yyMonth = $1;
  279.         yyDay = $2;
  280.     }
  281.     | tMONTH tUNUMBER ',' tUNUMBER {
  282.         yyMonth = $1;
  283.         yyDay = $2;
  284.         yyYear = $4;
  285.     }
  286.     | tUNUMBER tMONTH {
  287.         yyMonth = $2;
  288.         yyDay = $1;
  289.     }
  290.     | tUNUMBER tMONTH tUNUMBER {
  291.         yyMonth = $2;
  292.         yyDay = $1;
  293.         yyYear = $3;
  294.     }
  295.     ;
  296.  
  297. rel    : relunit tAGO {
  298.         yyRelSeconds = -yyRelSeconds;
  299.         yyRelMonth = -yyRelMonth;
  300.     }
  301.     | relunit
  302.     ;
  303.  
  304. relunit    : tUNUMBER tMINUTE_UNIT {
  305.         yyRelSeconds += $1 * $2 * 60L;
  306.     }
  307.     | tSNUMBER tMINUTE_UNIT {
  308.         yyRelSeconds += $1 * $2 * 60L;
  309.     }
  310.     | tMINUTE_UNIT {
  311.         yyRelSeconds += $1 * 60L;
  312.     }
  313.     | tSNUMBER tSEC_UNIT {
  314.         yyRelSeconds += $1;
  315.     }
  316.     | tUNUMBER tSEC_UNIT {
  317.         yyRelSeconds += $1;
  318.     }
  319.     | tSEC_UNIT {
  320.         yyRelSeconds++;
  321.     }
  322.     | tSNUMBER tMONTH_UNIT {
  323.         yyRelMonth += $1 * $2;
  324.     }
  325.     | tUNUMBER tMONTH_UNIT {
  326.         yyRelMonth += $1 * $2;
  327.     }
  328.     | tMONTH_UNIT {
  329.         yyRelMonth += $1;
  330.     }
  331.     ;
  332.  
  333. number    : tUNUMBER {
  334.         if (yyHaveTime && yyHaveDate && !yyHaveRel)
  335.         yyYear = $1;
  336.         else {
  337.         if ($1>10000) {
  338.             yyHaveDate++;
  339.             yyDay= ($1)%100;
  340.             yyMonth= ($1/100)%100;
  341.             yyYear = $1/10000;
  342.         }
  343.         else {
  344.             yyHaveTime++;
  345.             if ($1 < 100) {
  346.             yyHour = $1;
  347.             yyMinutes = 0;
  348.             }
  349.             else {
  350.                 yyHour = $1 / 100;
  351.                 yyMinutes = $1 % 100;
  352.             }
  353.             yySeconds = 0;
  354.             yyMeridian = MER24;
  355.             }
  356.         }
  357.     }
  358.     ;
  359.  
  360. o_merid    : /* NULL */ {
  361.         $$ = MER24;
  362.     }
  363.     | tMERIDIAN {
  364.         $$ = $1;
  365.     }
  366.     ;
  367.  
  368. %%
  369.  
  370. /* Month and day table. */
  371. static TABLE const MonthDayTable[] = {
  372.     { "january",    tMONTH,  1 },
  373.     { "february",    tMONTH,  2 },
  374.     { "march",        tMONTH,  3 },
  375.     { "april",        tMONTH,  4 },
  376.     { "may",        tMONTH,  5 },
  377.     { "june",        tMONTH,  6 },
  378.     { "july",        tMONTH,  7 },
  379.     { "august",        tMONTH,  8 },
  380.     { "september",    tMONTH,  9 },
  381.     { "sept",        tMONTH,  9 },
  382.     { "october",    tMONTH, 10 },
  383.     { "november",    tMONTH, 11 },
  384.     { "december",    tMONTH, 12 },
  385.     { "sunday",        tDAY, 0 },
  386.     { "monday",        tDAY, 1 },
  387.     { "tuesday",    tDAY, 2 },
  388.     { "tues",        tDAY, 2 },
  389.     { "wednesday",    tDAY, 3 },
  390.     { "wednes",        tDAY, 3 },
  391.     { "thursday",    tDAY, 4 },
  392.     { "thur",        tDAY, 4 },
  393.     { "thurs",        tDAY, 4 },
  394.     { "friday",        tDAY, 5 },
  395.     { "saturday",    tDAY, 6 },
  396.     { NULL }
  397. };
  398.  
  399. /* Time units table. */
  400. static TABLE const UnitsTable[] = {
  401.     { "year",        tMONTH_UNIT,    12 },
  402.     { "month",        tMONTH_UNIT,    1 },
  403.     { "fortnight",    tMINUTE_UNIT,    14 * 24 * 60 },
  404.     { "week",        tMINUTE_UNIT,    7 * 24 * 60 },
  405.     { "day",        tMINUTE_UNIT,    1 * 24 * 60 },
  406.     { "hour",        tMINUTE_UNIT,    60 },
  407.     { "minute",        tMINUTE_UNIT,    1 },
  408.     { "min",        tMINUTE_UNIT,    1 },
  409.     { "second",        tSEC_UNIT,    1 },
  410.     { "sec",        tSEC_UNIT,    1 },
  411.     { NULL }
  412. };
  413.  
  414. /* Assorted relative-time words. */
  415. static TABLE const OtherTable[] = {
  416.     { "tomorrow",    tMINUTE_UNIT,    1 * 24 * 60 },
  417.     { "yesterday",    tMINUTE_UNIT,    -1 * 24 * 60 },
  418.     { "today",        tMINUTE_UNIT,    0 },
  419.     { "now",        tMINUTE_UNIT,    0 },
  420.     { "last",        tUNUMBER,    -1 },
  421.     { "this",        tMINUTE_UNIT,    0 },
  422.     { "next",        tUNUMBER,    2 },
  423.     { "first",        tUNUMBER,    1 },
  424. /*  { "second",        tUNUMBER,    2 }, */
  425.     { "third",        tUNUMBER,    3 },
  426.     { "fourth",        tUNUMBER,    4 },
  427.     { "fifth",        tUNUMBER,    5 },
  428.     { "sixth",        tUNUMBER,    6 },
  429.     { "seventh",    tUNUMBER,    7 },
  430.     { "eighth",        tUNUMBER,    8 },
  431.     { "ninth",        tUNUMBER,    9 },
  432.     { "tenth",        tUNUMBER,    10 },
  433.     { "eleventh",    tUNUMBER,    11 },
  434.     { "twelfth",    tUNUMBER,    12 },
  435.     { "ago",        tAGO,    1 },
  436.     { NULL }
  437. };
  438.  
  439. /* The timezone table. */
  440. /* Some of these are commented out because a time_t can't store a float. */
  441. static TABLE const TimezoneTable[] = {
  442.     { "gmt",    tZONE,     HOUR ( 0) },    /* Greenwich Mean */
  443.     { "ut",    tZONE,     HOUR ( 0) },    /* Universal (Coordinated) */
  444.     { "utc",    tZONE,     HOUR ( 0) },
  445.     { "wet",    tZONE,     HOUR ( 0) },    /* Western European */
  446.     { "bst",    tDAYZONE,  HOUR ( 0) },    /* British Summer */
  447.     { "wat",    tZONE,     HOUR ( 1) },    /* West Africa */
  448.     { "at",    tZONE,     HOUR ( 2) },    /* Azores */
  449. #if    0
  450.     /* For completeness.  BST is also British Summer, and GST is
  451.      * also Guam Standard. */
  452.     { "bst",    tZONE,     HOUR ( 3) },    /* Brazil Standard */
  453.     { "gst",    tZONE,     HOUR ( 3) },    /* Greenland Standard */
  454. #endif
  455. #if 0
  456.     { "nft",    tZONE,     HOUR (3.5) },    /* Newfoundland */
  457.     { "nst",    tZONE,     HOUR (3.5) },    /* Newfoundland Standard */
  458.     { "ndt",    tDAYZONE,  HOUR (3.5) },    /* Newfoundland Daylight */
  459. #endif
  460.     { "ast",    tZONE,     HOUR ( 4) },    /* Atlantic Standard */
  461.     { "adt",    tDAYZONE,  HOUR ( 4) },    /* Atlantic Daylight */
  462.     { "est",    tZONE,     HOUR ( 5) },    /* Eastern Standard */
  463.     { "edt",    tDAYZONE,  HOUR ( 5) },    /* Eastern Daylight */
  464.     { "cst",    tZONE,     HOUR ( 6) },    /* Central Standard */
  465.     { "cdt",    tDAYZONE,  HOUR ( 6) },    /* Central Daylight */
  466.     { "mst",    tZONE,     HOUR ( 7) },    /* Mountain Standard */
  467.     { "mdt",    tDAYZONE,  HOUR ( 7) },    /* Mountain Daylight */
  468.     { "pst",    tZONE,     HOUR ( 8) },    /* Pacific Standard */
  469.     { "pdt",    tDAYZONE,  HOUR ( 8) },    /* Pacific Daylight */
  470.     { "yst",    tZONE,     HOUR ( 9) },    /* Yukon Standard */
  471.     { "ydt",    tDAYZONE,  HOUR ( 9) },    /* Yukon Daylight */
  472.     { "hst",    tZONE,     HOUR (10) },    /* Hawaii Standard */
  473.     { "hdt",    tDAYZONE,  HOUR (10) },    /* Hawaii Daylight */
  474.     { "cat",    tZONE,     HOUR (10) },    /* Central Alaska */
  475.     { "ahst",    tZONE,     HOUR (10) },    /* Alaska-Hawaii Standard */
  476.     { "nt",    tZONE,     HOUR (11) },    /* Nome */
  477.     { "idlw",    tZONE,     HOUR (12) },    /* International Date Line West */
  478.     { "cet",    tZONE,     -HOUR (1) },    /* Central European */
  479.     { "met",    tZONE,     -HOUR (1) },    /* Middle European */
  480.     { "mewt",    tZONE,     -HOUR (1) },    /* Middle European Winter */
  481.     { "mest",    tDAYZONE,  -HOUR (1) },    /* Middle European Summer */
  482.     { "mesz",    tDAYZONE,  -HOUR (1) },    /* Middle European Summer */
  483.     { "swt",    tZONE,     -HOUR (1) },    /* Swedish Winter */
  484.     { "sst",    tDAYZONE,  -HOUR (1) },    /* Swedish Summer */
  485.     { "fwt",    tZONE,     -HOUR (1) },    /* French Winter */
  486.     { "fst",    tDAYZONE,  -HOUR (1) },    /* French Summer */
  487.     { "eet",    tZONE,     -HOUR (2) },    /* Eastern Europe, USSR Zone 1 */
  488.     { "bt",    tZONE,     -HOUR (3) },    /* Baghdad, USSR Zone 2 */
  489. #if 0
  490.     { "it",    tZONE,     -HOUR (3.5) },/* Iran */
  491. #endif
  492.     { "zp4",    tZONE,     -HOUR (4) },    /* USSR Zone 3 */
  493.     { "zp5",    tZONE,     -HOUR (5) },    /* USSR Zone 4 */
  494. #if 0
  495.     { "ist",    tZONE,     -HOUR (5.5) },/* Indian Standard */
  496. #endif
  497.     { "zp6",    tZONE,     -HOUR (6) },    /* USSR Zone 5 */
  498. #if    0
  499.     /* For completeness.  NST is also Newfoundland Standard, and SST is
  500.      * also Swedish Summer. */
  501.     { "nst",    tZONE,     -HOUR (6.5) },/* North Sumatra */
  502.     { "sst",    tZONE,     -HOUR (7) },    /* South Sumatra, USSR Zone 6 */
  503. #endif    /* 0 */
  504.     { "wast",    tZONE,     -HOUR (7) },    /* West Australian Standard */
  505.     { "wadt",    tDAYZONE,  -HOUR (7) },    /* West Australian Daylight */
  506. #if 0
  507.     { "jt",    tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
  508. #endif
  509.     { "cct",    tZONE,     -HOUR (8) },    /* China Coast, USSR Zone 7 */
  510.     { "jst",    tZONE,     -HOUR (9) },    /* Japan Standard, USSR Zone 8 */
  511. #if 0
  512.     { "cast",    tZONE,     -HOUR (9.5) },/* Central Australian Standard */
  513.     { "cadt",    tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
  514. #endif
  515.     { "east",    tZONE,     -HOUR (10) },    /* Eastern Australian Standard */
  516.     { "eadt",    tDAYZONE,  -HOUR (10) },    /* Eastern Australian Daylight */
  517.     { "gst",    tZONE,     -HOUR (10) },    /* Guam Standard, USSR Zone 9 */
  518.     { "nzt",    tZONE,     -HOUR (12) },    /* New Zealand */
  519.     { "nzst",    tZONE,     -HOUR (12) },    /* New Zealand Standard */
  520.     { "nzdt",    tDAYZONE,  -HOUR (12) },    /* New Zealand Daylight */
  521.     { "idle",    tZONE,     -HOUR (12) },    /* International Date Line East */
  522.     {  NULL  }
  523. };
  524.  
  525. /* Military timezone table. */
  526. static TABLE const MilitaryTable[] = {
  527.     { "a",    tZONE,    HOUR (  1) },
  528.     { "b",    tZONE,    HOUR (  2) },
  529.     { "c",    tZONE,    HOUR (  3) },
  530.     { "d",    tZONE,    HOUR (  4) },
  531.     { "e",    tZONE,    HOUR (  5) },
  532.     { "f",    tZONE,    HOUR (  6) },
  533.     { "g",    tZONE,    HOUR (  7) },
  534.     { "h",    tZONE,    HOUR (  8) },
  535.     { "i",    tZONE,    HOUR (  9) },
  536.     { "k",    tZONE,    HOUR ( 10) },
  537.     { "l",    tZONE,    HOUR ( 11) },
  538.     { "m",    tZONE,    HOUR ( 12) },
  539.     { "n",    tZONE,    HOUR (- 1) },
  540.     { "o",    tZONE,    HOUR (- 2) },
  541.     { "p",    tZONE,    HOUR (- 3) },
  542.     { "q",    tZONE,    HOUR (- 4) },
  543.     { "r",    tZONE,    HOUR (- 5) },
  544.     { "s",    tZONE,    HOUR (- 6) },
  545.     { "t",    tZONE,    HOUR (- 7) },
  546.     { "u",    tZONE,    HOUR (- 8) },
  547.     { "v",    tZONE,    HOUR (- 9) },
  548.     { "w",    tZONE,    HOUR (-10) },
  549.     { "x",    tZONE,    HOUR (-11) },
  550.     { "y",    tZONE,    HOUR (-12) },
  551.     { "z",    tZONE,    HOUR (  0) },
  552.     { NULL }
  553. };
  554.  
  555.  
  556.  
  557.  
  558. /* ARGSUSED */
  559. static int
  560. yyerror (s)
  561.     char    *s;
  562. {
  563.   return 0;
  564. }
  565.  
  566.  
  567. static time_t
  568. ToSeconds (Hours, Minutes, Seconds, Meridian)
  569.     time_t    Hours;
  570.     time_t    Minutes;
  571.     time_t    Seconds;
  572.     MERIDIAN    Meridian;
  573. {
  574.   if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  575.     return -1;
  576.   switch (Meridian) {
  577.   case MER24:
  578.     if (Hours < 0 || Hours > 23)
  579.       return -1;
  580.     return (Hours * 60L + Minutes) * 60L + Seconds;
  581.   case MERam:
  582.     if (Hours < 1 || Hours > 12)
  583.       return -1;
  584.     if (Hours == 12)
  585.       Hours = 0;
  586.     return (Hours * 60L + Minutes) * 60L + Seconds;
  587.   case MERpm:
  588.     if (Hours < 1 || Hours > 12)
  589.       return -1;
  590.     if (Hours == 12)
  591.       Hours = 0;
  592.     return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  593.   default:
  594.     abort ();
  595.   }
  596.   /* NOTREACHED */
  597. }
  598.  
  599.  
  600. static time_t
  601. Convert (Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
  602.     time_t    Month;
  603.     time_t    Day;
  604.     time_t    Year;
  605.     time_t    Hours;
  606.     time_t    Minutes;
  607.     time_t    Seconds;
  608.     MERIDIAN    Meridian;
  609.     DSTMODE    DSTmode;
  610. {
  611.   static int DaysInMonth[12] = {
  612.     31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  613.   };
  614.   time_t    tod;
  615.   time_t    Julian;
  616.   int        i;
  617.  
  618.   if (Year < 0)
  619.     Year = -Year;
  620.   if (Year < DOOMSDAY-2000)
  621.     Year += 2000;
  622.   else if (Year < 100)
  623.     Year += 1900;
  624.   DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  625.     ? 29 : 28;
  626.   if (Year < EPOCH || Year >= DOOMSDAY
  627.       || Month < 1 || Month > 12
  628.       /* Lint fluff:  "conversion from long may lose accuracy" */
  629.       || Day < 1 || Day > DaysInMonth[(int)--Month])
  630.     return -1;
  631.  
  632.   for (Julian = Day - 1, i = 0; i < Month; i++)
  633.     Julian += DaysInMonth[i];
  634.   for (i = EPOCH; i < Year; i++)
  635.     Julian += 365 + (i % 4 == 0);
  636.   Julian *= SECSPERDAY;
  637.   Julian += yyTimezone * 60L;
  638.   if ((tod = ToSeconds (Hours, Minutes, Seconds, Meridian)) < 0)
  639.     return -1;
  640.   Julian += tod;
  641.   if (DSTmode == DSTon
  642.       || (DSTmode == DSTmaybe && localtime (&Julian)->tm_isdst))
  643.     Julian -= 60 * 60;
  644.   return Julian;
  645. }
  646.  
  647.  
  648. static time_t
  649. DSTcorrect (Start, Future)
  650.     time_t    Start;
  651.     time_t    Future;
  652. {
  653.   time_t    StartDay;
  654.   time_t    FutureDay;
  655.  
  656.   StartDay = (localtime (&Start)->tm_hour + 1) % 24;
  657.   FutureDay = (localtime (&Future)->tm_hour + 1) % 24;
  658.   return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  659. }
  660.  
  661.  
  662. static time_t
  663. RelativeDate (Start, DayOrdinal, DayNumber)
  664.     time_t    Start;
  665.     time_t    DayOrdinal;
  666.     time_t    DayNumber;
  667. {
  668.   struct tm    *tm;
  669.   time_t    now;
  670.  
  671.   now = Start;
  672.   tm = localtime (&now);
  673.   now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  674.   now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  675.   return DSTcorrect (Start, now);
  676. }
  677.  
  678.  
  679. static time_t
  680. RelativeMonth (Start, RelMonth)
  681.     time_t    Start;
  682.     time_t    RelMonth;
  683. {
  684.   struct tm    *tm;
  685.   time_t    Month;
  686.   time_t    Year;
  687.  
  688.   if (RelMonth == 0)
  689.     return 0;
  690.   tm = localtime (&Start);
  691.   Month = 12 * (1900 + tm->tm_year) + tm->tm_mon + RelMonth;
  692.   Year = Month / 12;
  693.   Month = Month % 12 + 1;
  694.   return DSTcorrect (Start,
  695.              Convert (Month, (time_t)tm->tm_mday, Year,
  696.                   (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  697.                   MER24, DSTmaybe));
  698. }
  699.  
  700.  
  701. static int
  702. LookupWord (buff)
  703.     char        *buff;
  704. {
  705.   register char    *p;
  706.   register char    *q;
  707.   register const TABLE    *tp;
  708.   int            i;
  709.   int            abbrev;
  710.  
  711.   /* Make it lowercase. */
  712.   for (p = buff; *p; p++)
  713.     if (isupper (*p))
  714.       *p = tolower (*p);
  715.  
  716.   if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) {
  717.     yylval.Meridian = MERam;
  718.     return tMERIDIAN;
  719.   }
  720.   if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) {
  721.     yylval.Meridian = MERpm;
  722.     return tMERIDIAN;
  723.   }
  724.  
  725.   /* See if we have an abbreviation for a month. */
  726.   if (strlen (buff) == 3)
  727.     abbrev = 1;
  728.   else if (strlen (buff) == 4 && buff[3] == '.') {
  729.     abbrev = 1;
  730.     buff[3] = '\0';
  731.   }
  732.   else
  733.     abbrev = 0;
  734.  
  735.   for (tp = MonthDayTable; tp->name; tp++) {
  736.     if (abbrev) {
  737.       if (strncmp (buff, tp->name, 3) == 0) {
  738.     yylval.Number = tp->value;
  739.     return tp->type;
  740.       }
  741.     }
  742.     else if (strcmp (buff, tp->name) == 0) {
  743.       yylval.Number = tp->value;
  744.       return tp->type;
  745.     }
  746.   }
  747.  
  748.   for (tp = TimezoneTable; tp->name; tp++)
  749.     if (strcmp (buff, tp->name) == 0) {
  750.       yylval.Number = tp->value;
  751.       return tp->type;
  752.     }
  753.  
  754.   if (strcmp (buff, "dst") == 0)
  755.     return tDST;
  756.  
  757.   for (tp = UnitsTable; tp->name; tp++)
  758.     if (strcmp (buff, tp->name) == 0) {
  759.       yylval.Number = tp->value;
  760.       return tp->type;
  761.     }
  762.  
  763.   /* Strip off any plural and try the units table again. */
  764.   i = strlen (buff) - 1;
  765.   if (buff[i] == 's') {
  766.     buff[i] = '\0';
  767.     for (tp = UnitsTable; tp->name; tp++)
  768.       if (strcmp (buff, tp->name) == 0) {
  769.     yylval.Number = tp->value;
  770.     return tp->type;
  771.       }
  772.     buff[i] = 's';        /* Put back for "this" in OtherTable. */
  773.   }
  774.  
  775.   for (tp = OtherTable; tp->name; tp++)
  776.     if (strcmp (buff, tp->name) == 0) {
  777.       yylval.Number = tp->value;
  778.       return tp->type;
  779.     }
  780.  
  781.   /* Military timezones. */
  782.   if (buff[1] == '\0' && isalpha (*buff)) {
  783.     for (tp = MilitaryTable; tp->name; tp++)
  784.       if (strcmp (buff, tp->name) == 0) {
  785.     yylval.Number = tp->value;
  786.     return tp->type;
  787.       }
  788.   }
  789.  
  790.   /* Drop out any periods and try the timezone table again. */
  791.   for (i = 0, p = q = buff; *q; q++)
  792.     if (*q != '.')
  793.       *p++ = *q;
  794.     else
  795.       i++;
  796.   *p = '\0';
  797.   if (i)
  798.     for (tp = TimezoneTable; tp->name; tp++)
  799.       if (strcmp (buff, tp->name) == 0) {
  800.     yylval.Number = tp->value;
  801.     return tp->type;
  802.       }
  803.  
  804.   return tID;
  805. }
  806.  
  807.  
  808. static int
  809. yylex ()
  810. {
  811.   register char    c;
  812.   register char    *p;
  813.   char        buff[20];
  814.   int            Count;
  815.   int            sign;
  816.  
  817.   for ( ; ; ) {
  818.     while (isspace (*yyInput))
  819.       yyInput++;
  820.  
  821.     if (isdigit (c = *yyInput) || c == '-' || c == '+') {
  822.       if (c == '-' || c == '+') {
  823.     sign = c == '-' ? -1 : 1;
  824.     if (!isdigit (*++yyInput))
  825.       /* skip the '-' sign */
  826.       continue;
  827.       }
  828.       else
  829.     sign = 0;
  830.       for (yylval.Number = 0; isdigit (c = *yyInput++); )
  831.     yylval.Number = 10 * yylval.Number + c - '0';
  832.       yyInput--;
  833.       if (sign < 0)
  834.     yylval.Number = -yylval.Number;
  835.       return sign ? tSNUMBER : tUNUMBER;
  836.     }
  837.     if (isalpha (c)) {
  838.       for (p = buff; isalpha (c = *yyInput++) || c == '.'; )
  839.     if (p < &buff[sizeof buff - 1])
  840.       *p++ = c;
  841.       *p = '\0';
  842.       yyInput--;
  843.       return LookupWord (buff);
  844.     }
  845.     if (c != '(')
  846.       return *yyInput++;
  847.     Count = 0;
  848.     do {
  849.       c = *yyInput++;
  850.       if (c == '\0')
  851.     return c;
  852.       if (c == '(')
  853.     Count++;
  854.       else if (c == ')')
  855.     Count--;
  856.     } while (Count > 0);
  857.   }
  858. }
  859.  
  860. #define TM_YEAR_ORIGIN 1900
  861.  
  862. /* Yield A - B, measured in seconds.  */
  863. static long
  864. difftm (a, b)
  865.      struct tm *a, *b;
  866. {
  867.   int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
  868.   int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
  869.   long days = (
  870.            /* difference in day of year */
  871.            a->tm_yday - b->tm_yday
  872.            /* + intervening leap days */
  873.            +  ((ay >> 2) - (by >> 2))
  874.            -  (ay/100 - by/100)
  875.            +  ((ay/100 >> 2) - (by/100 >> 2))
  876.            /* + difference in years * 365 */
  877.            +  (long)(ay-by) * 365
  878.            );
  879.   return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
  880.           + (a->tm_min - b->tm_min))
  881.       + (a->tm_sec - b->tm_sec));
  882. }
  883.  
  884. time_t
  885. get_date (p, now)
  886.     char        *p;
  887.     struct timeb    *now;
  888. {
  889.   struct tm        *tm, gmt;
  890.   struct timeb    ftz;
  891.   time_t        Start;
  892.   time_t        tod;
  893.  
  894.   yyInput = p;
  895.   if (now == NULL) {
  896.     now = &ftz;
  897.     (void)time (&ftz.time);
  898.  
  899.     if (! (tm = gmtime (&ftz.time)))
  900.       return -1;
  901.     gmt = *tm;            /* Make a copy, in case localtime modifies *tm.  */
  902.  
  903.     if (! (tm = localtime (&ftz.time)))
  904.       return -1;
  905.  
  906.     ftz.timezone = difftm (&gmt, tm) / 60;
  907.     if (tm->tm_isdst)
  908.       ftz.timezone += 60;
  909.   }
  910.  
  911.   tm = localtime (&now->time);
  912.   yyYear = tm->tm_year;
  913.   yyMonth = tm->tm_mon + 1;
  914.   yyDay = tm->tm_mday;
  915.   yyTimezone = now->timezone;
  916.   yyDSTmode = DSTmaybe;
  917.   yyHour = 0;
  918.   yyMinutes = 0;
  919.   yySeconds = 0;
  920.   yyMeridian = MER24;
  921.   yyRelSeconds = 0;
  922.   yyRelMonth = 0;
  923.   yyHaveDate = 0;
  924.   yyHaveDay = 0;
  925.   yyHaveRel = 0;
  926.   yyHaveTime = 0;
  927.   yyHaveZone = 0;
  928.  
  929.   if (yyparse ()
  930.       || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  931.     return -1;
  932.  
  933.   if (yyHaveDate || yyHaveTime || yyHaveDay) {
  934.     Start = Convert (yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  935.              yyMeridian, yyDSTmode);
  936.     if (Start < 0)
  937.       return -1;
  938.   }
  939.   else {
  940.     Start = now->time;
  941.     if (!yyHaveRel)
  942.       Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  943.   }
  944.  
  945.   Start += yyRelSeconds;
  946.   Start += RelativeMonth (Start, yyRelMonth);
  947.  
  948.   if (yyHaveDay && !yyHaveDate) {
  949.     tod = RelativeDate (Start, yyDayOrdinal, yyDayNumber);
  950.     Start += tod;
  951.   }
  952.  
  953.   /* Have to do *something* with a legitimate -1 so it's distinguishable
  954.    * from the error return value.  (Alternately could set errno on error.) */
  955.   return Start == -1 ? 0 : Start;
  956. }
  957.  
  958.  
  959. #if    defined (TEST)
  960.  
  961. /* ARGSUSED */
  962. int
  963. main (ac, av)
  964.     int        ac;
  965.     char    *av[];
  966. {
  967.   char buff[MAX_BUFF_LEN + 1];
  968.   time_t d;
  969.  
  970.   (void)printf ("Enter date, or blank line to exit.\n\t> ");
  971.   (void)fflush (stdout);
  972.  
  973.   buff[MAX_BUFF_LEN] = 0;
  974.   while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0]) {
  975.     d = get_date (buff, (struct timeb *)NULL);
  976.     if (d == -1)
  977.       (void)printf ("Bad format - couldn't convert.\n");
  978.     else
  979.       (void)printf ("%s", ctime (&d));
  980.     (void)printf ("\t> ");
  981.     (void)fflush (stdout);
  982.   }
  983.   exit (0);
  984.   /* NOTREACHED */
  985. }
  986. #endif    /* defined (TEST) */
  987.